;; This file is part of scheme-GNUnet.
;; Copyright (C) 2021 GNUnet e.V.
;;
;; scheme-GNUnet is free software: you can redistribute it and/or modify it
;; under the terms of the GNU Affero General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version.
;;
;; scheme-GNUnet is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;
;; SPDX-License-Identifier: AGPL-3.0-or-later

;; Description from RFC 792:
;; [...]
;; ICMP messages are sent in several situations:  for example, when a
;; datagram cannot reach its destination, when the gateway does not have
;; the buffering capacity to forward a datagram, and when the gateway
;; can direct the host to send traffic on a shorter route.
;; [...]

;; While (scheme-)GNUnet does not interect much with the ICMP
;; protocol (except VPN, maybe?), understanding ICMP somewhat
;; can be useful for printing informative error messages.
;;
;; (On Linux, IP_RECVERR can be used on some Internet sockets
;; (but not for SOCK_STREAM) to receive some ICMP errors.)

(define-library (gnu gnunet icmp struct)
  (export icmp-type
	  icmp-type?
	  icmp-code/destination-unreachable
	  icmp-code/time-exceeded
	  icmp-code/parameter-problem
	  icmp-code/destination-unreachable?
	  icmp-code/time-exceeded?
	  icmp-code/parameter-problem?
	  /icmp/destination-unreachable
	  /icmp/time-exceeded
	  /icmp/parameter-problem)
  (import (only (gnu extractor enum)
		define-enumeration value)
	  (only (gnu gnunet netstruct syntactic)
		define-type structure/packed)
	  (only (gnu gnunet netstruct procedural)
		u8)
	  (only (rnrs base) begin quote))
  (begin

    ;; Internet RFC 792
    (define-enumeration (icmp-type icmp-type?)
      (#:documentation "Type of ICMP packet")
      (#:max 256)
      (#:known
       (value
	(symbol icmp:echo-reply)
	(index 0))
       (value
	(symbol icmp:destination-unreachable)
	(index 3))
       (value
	(symbol icmp:source-quench)
	(index 4))
       (value
	(symbol icmp:redirect)
	(index 5))
       (value
	(symbol icmp:echo)
	(index 8))
       (value
	(symbol icmp:time-exceeded)
	(index 11))
       (value
	(symbol icmp:parameter-problem)
	(index 12))
       (value
	(symbol icmp:timestamp)
	(index 13))
       (value
	(symbol icmp:timestamp-reply)
	(index 14))
       (value
	(symbol icmp:information-request)
	(index 15))
       (value
	(symbol icmp:information-reply)
	(index 16))))

    (define-enumeration (icmp-code/destination-unreachable
			 icmp-code/destination-unreachable?)
      (#:documentation "something is unreachable")
      (#:max 256)
      (#:known
       (value
	(symbol icmp:network-unreachable)
	(index 0))
       (value
	(symbol icmp:host-unreachable)
	(index 1))
       (value
	(symbol icmp:protocol-unreachable)
	(index 2))
       (value
	(symbol icmp:port-unreachable)
	(index 3))
       (value
	(symbol icmp:fragmentation-needed)
	(index 4))
       (value
	(symbol icmp:source-route-failed)
	(index 5))))

    (define-enumeration (icmp-code/time-exceeded
			 icmp-code/time-exceeded?)
      (#:documentation "time-out")
      (#:max 256)
      (#:known
       (value
	(symbol icmp:ttl-exceeded-in-transit)
	(index 0))
       (value
	(symbol icmp:fragment-reassembly-time-exceeded)
	(index 1))))

    (define-enumeration (icmp-code/parameter-problem
			 icmp-code/parameter-problem?)
      (#:documentation "incorrect datagram headers")
      (#:max 256)
      (#:known
       (value
	;; provisional name
	(symbol icmp:pointer-indicates-the-error)
	(index 0))))
    

    (define-type /icmp/destination-unreachable
      (structure/packed
       (synopsis "a")
       (documentation
	"Followed by the internet header + 64 bits of the datagram data")
       (field (type u8)
	      (properties '((enum-type icmp-type)
			    (enum-value icmp:destination-unreachable))))
       (field (code u8)
	      (properties '((enum-type icmp-code/destination-unreachable))))
       (field (unused u8))))

    (define-type /icmp/time-exceeded
      (structure/packed
       (documentation
	"Followed by the internet header + 64 bits of the datagram data")
       (field (type u8)
	      (properties '((enum-type icmp-type)
			    (enum-value icmp:time-exceeded))))
       (field (code u8)
	      (properties '((enum-type icmp-code/time-exceeded))))))

    (define-type /icmp/parameter-problem
      (structure/packed
       (documentation
	"Followed by the internet header + 64 bits of the datagram data")
       (field (type u8)
	      (properties '((enum-type icmp-type)
			    (enum-value icmp:parameter-problem))))
       (field (code u8)
	      (properties '((enum-type icmp-code/parameter-problem))))
       (field (parameter u8)
	      (synopsis "If code is 0, the IP option type"))))))
